package org.simplespringframework.aop;

import org.simplespringframework.BeanContainer;
import org.simplespringframework.aop.annotation.Aspect;
import org.simplespringframework.aop.annotation.Order;
import org.simplespringframework.aop.aspect.AspectInfo;
import org.simplespringframework.aop.aspect.DefaultAspect;
import org.simplespringframework.util.ValidationUtil;

import java.lang.annotation.Annotation;
import java.util.*;

public class AspectWeaver {

    private BeanContainer beanContainer;

    public AspectWeaver() {
        beanContainer = BeanContainer.getInstance();
    }


    public void doAop() {
        // 1.获取所有的切面类
        Set<Class<?>> aspectSet =  beanContainer.getClassesByAnnotation(Aspect.class);
        // 2.将切面类按照不同的织入目标进行切分
        Map<Class<? extends Annotation>, List<AspectInfo>> categorizedMap = new HashMap<>();
        if (ValidationUtil.isEmpty(aspectSet)) {
            return;
        }
        for (Class<?> aspectClass : aspectSet) {
            if (verifyAspect(aspectClass)) {
                categorizedAspect(categorizedMap, aspectClass);
            } else {
                throw new RuntimeException("当前aspect可能未标记,未继承DefaultAspect");
            }
        }
        // 3.按照不同的织入目标分别去按序织入Aspect的逻辑
        if (ValidationUtil.isEmpty(categorizedMap)) {
            return;
        }
        for (Class<? extends Annotation> category : categorizedMap.keySet()) {
            weaveByCategory(category,categorizedMap.get(category));
        }
    }

    private void weaveByCategory(Class<? extends Annotation> category, List<AspectInfo> aspectInfos) {
        // 1.获取被代理类的集合
        Set<Class<?>> classSet = beanContainer.getClassesByAnnotation(category);
        if (ValidationUtil.isEmpty(classSet)) {
            return;
        }
        // 2.遍历被代理类,分别为每个被代理类生成动态代理实例
        for (Class<?> targetClass : classSet) {
            // 创建动态代理对象
            AspectListExecutor aspectListExecutor = new AspectListExecutor(targetClass, aspectInfos);
            Object proxyBean = ProxyCreator.createProxy(targetClass, aspectListExecutor);
            // 3.将动态代理对象实例添加到容器里, 取代未被代理前的类实例
            beanContainer.addBean(targetClass, proxyBean);
        }

    }


    // 将切面类按照不同的织入目标进行切分
    private void categorizedAspect(Map<Class<? extends Annotation>, List<AspectInfo>> categorizedMap, Class<?> aspectClass) {

        Order orderTag = aspectClass.getAnnotation(Order.class);
        Aspect aspectTag = aspectClass.getAnnotation(Aspect.class);
        DefaultAspect aspect = (DefaultAspect) beanContainer.getBean(aspectClass);

        AspectInfo aspectInfo = new AspectInfo(orderTag.value(), aspect);

        if (!categorizedMap.containsKey(aspectTag.value())) {
            ArrayList<AspectInfo> infoArrayList = new ArrayList<>();
            infoArrayList.add(aspectInfo);
            categorizedMap.put(aspectTag.value(), infoArrayList);
        } else {
            List<AspectInfo> aspectInfoList = categorizedMap.get(aspectTag.value());
            aspectInfoList.add(aspectInfo);
        }
    }


    // 框架中一定要遵守Aspect类添加@Aspect 和 @order标签的规范, 同时,必须继承自DefaultAspect.class
    // @Aspect的属性值不能是它本身
    private boolean verifyAspect(Class<?> aspectClass) {
        return aspectClass.isAnnotationPresent(Aspect.class) &&
                aspectClass.isAnnotationPresent(Order.class) &&
                DefaultAspect.class.isAssignableFrom(aspectClass) &&
                aspectClass.getAnnotation(Aspect.class).value() != Aspect.class;
    }

}
